//==============================================================================
//
//  File        : mmpf_dma.c
//  Description : Firmware Graphic Control Function (DMA portion)
//  Author      : Alan Wu
//  Revision    : 1.0
//
//==============================================================================
#include "config_fw.h"
#include "includes_fw.h"
#include "mmpf_dma.h"
#include "mmp_reg_dma.h"
#include "lib_retina.h"

#if SUPPORT_DMA
//static MMPF_DMA_ROT_DATA gDmaRotateData[DMA_R_NUM];
static DmaCallBackFunc *CallBackFuncM0 = NULL;
static DmaCallBackFunc *CallBackFuncM1 = NULL;
static DmaCallBackFunc *CallBackFuncR0 = NULL;
static DmaCallBackFunc *CallBackFuncR1 = NULL;


static MMPF_OS_SEMID  gDMAMoveSemID;
static MMPF_OS_SEMID  gDMARotSemID;
static MMP_BOOL gbDmaFreeM0;
static MMP_BOOL gbDmaFreeM1;

static MMP_BOOL gbDmaFreeR0;
static MMP_BOOL gbDmaFreeR1;

/*static*/ MMP_UBYTE gbDmaEnCount = 0;
//static MMPF_DAM_ROT_DATA gDmaRotateData[DMA_R_NUM];

extern OS_EVENT		*os_sem_tbl[MMPF_OS_SEMID_MAX];
//==============================================================================
//
//                              VARIABLES
//
//==============================================================================

//==============================================================================
//
//                              FUNCTION PROTOTYPES
//
//==============================================================================
/*static MMP_ERR MMPF_DMA_Rotate(MMP_ULONG ulSrcaddr, MMP_ULONG ulDstaddr,MMP_USHORT usSrcwidth, MMP_USHORT usSrcheight,
                        MMPF_GRAPHICS_COLORDEPTH colordepth, MMPF_DMA_R_TYPE rotatetype,
                        MMP_USHORT usSrcOffest, MMP_USHORT usDstOffset, MMPF_DMA_R_ID Dmarid, MMP_BOOL mirrorEnable, MMPF_DMA_R_MIRROR_TYPE mirrortype);

*/
//------------------------------------------------------------------------------
//  Function    : MMPF_DMA_Initialize
//  Description :
//  Note        : put in sys_task:main() or XX_Task() (ex: dsc_Task)
//------------------------------------------------------------------------------
MMP_ERR MMPF_DMA_Initialize(void)
{
    AITPS_AIC   pAIC = AITC_BASE_AIC;
    //AITPS_GBL   pGBL = AITC_BASE_GBL;

    RTNA_AIC_Open(pAIC, AIC_SRC_DMA, dma_isr_a,
                AIC_INT_TO_IRQ | AIC_SRCTYPE_HIGH_LEVEL_SENSITIVE | 3);
    RTNA_AIC_IRQ_En(pAIC, AIC_SRC_DMA);
	
	gDMAMoveSemID = MMPF_OS_CreateSem(2);
	gDMARotSemID = MMPF_OS_CreateSem(2);
	
    gbDmaFreeM0 = MMP_TRUE;
    gbDmaFreeM1 = MMP_TRUE;
    
	gbDmaFreeR0	= MMP_TRUE;
	gbDmaFreeR1 = MMP_TRUE;
	
    CallBackFuncM0 = NULL;
    CallBackFuncM1 = NULL;
    CallBackFuncR0  = NULL;
    
	CallBackFuncR1  = NULL;
	//temp solution to enable clock. clock enable operation must move to Host side
	//pGBL->GBL_CLK_EN |= GBL_CLK_DMA;

    return MMP_ERR_NONE;
}

//------------------------------------------------------------------------------
//  Function    : MMPF_DMA_ISR
//  Description :
//------------------------------------------------------------------------------
void MMPF_DMA_ISR(void)
{
    AITPS_DMA   pDMA = AITC_BASE_DMA;
    MMP_USHORT  intsrc;
    
    intsrc = pDMA->DMA_INT_CPU_SR & pDMA->DMA_INT_CPU_EN;
    pDMA->DMA_INT_CPU_SR = intsrc;
	    
    if (intsrc & DMA_INT_M0) {

        gbDmaFreeM0 = MMP_TRUE;
        if (CallBackFuncM0)
            CallBackFuncM0();
    }

    if (intsrc & DMA_INT_R0) {

        gbDmaFreeR0 = MMP_TRUE;
        if (CallBackFuncR0)
            CallBackFuncR0();
    }
}

//------------------------------------------------------------------------------
//  Function    : MMPF_DMA_MoveData0
//  Description :
//  Note        : 1. The function doesn't use in ISR, because it called MMPF_OS_AcquireSem.
//                2. The execute time of DMARetFun must transient, because MMPF_DMA_ISR used the
//                   Callback function.
//------------------------------------------------------------------------------
MMP_ERR MMPF_DMA_MoveData0(MMP_ULONG ulSrcaddr, MMP_ULONG ulDstaddr,
                            MMP_ULONG ulCount, MMPF_DMA_M_LOFFS_DATA* ptrLineOffset,
                            DmaCallBackFunc *CallBackFunc)
{
	AITPS_DMA pDMA = AITC_BASE_DMA;
	#if OS_CRITICAL_METHOD == 3
    OS_CPU_SR   cpu_sr = 0;
	#endif

    if (gbDmaFreeM0 == MMP_FALSE) {
        pDMA->DMA_INT_CPU_SR = DMA_INT_M0;
        RTNA_DBG_Str(0, "DMA_M busy\r\n");
        return 1;
    }

    gbDmaEnCount++;
    gbDmaFreeM0 = MMP_FALSE;
    CallBackFuncM0 = CallBackFunc;

    pDMA->DMA_M[MMPF_DMA_M_0].DMA_M_SRC_ADDR = ulSrcaddr;
    pDMA->DMA_M[MMPF_DMA_M_0].DMA_M_DST_ADDR = ulDstaddr;
    pDMA->DMA_M[MMPF_DMA_M_0].DMA_M_BYTE_CNT = ulCount;

    if (ptrLineOffset) {
        pDMA->DMA_M_LOFFS[MMPF_DMA_M_0].DMA_M_SRC_LOFFS_W = ptrLineOffset->SrcWidth;
        pDMA->DMA_M_LOFFS[MMPF_DMA_M_0].DMA_M_SRC_LOFFS_OFFS = ptrLineOffset->SrcOffset;
        pDMA->DMA_M_LOFFS[MMPF_DMA_M_0].DMA_M_DST_LOFFS_W = ptrLineOffset->DstWidth;
        pDMA->DMA_M_LOFFS[MMPF_DMA_M_0].DMA_M_DST_LOFFS_OFFS = ptrLineOffset->DstOffset;
        pDMA->DMA_M0_LOFFS_EN |= DMA_LOFFS_ENABLE;
    }
    else {
        pDMA->DMA_M0_LOFFS_EN &= ~DMA_LOFFS_ENABLE;
    }

#if 1
    pDMA->DMA_INT_CPU_SR = DMA_INT_M0;
    OS_ENTER_CRITICAL();
    pDMA->DMA_INT_CPU_EN |= DMA_INT_M0; //TBD, check if enabled at dma init
    OS_EXIT_CRITICAL();

    pDMA->DMA_EN = DMA_M_ENABLE;
#else
    MMPF_PLL_WaitCount(0x7FFF); //Debug test only, Ben_20120322
    pDMA->DMA_EN = DMA_M_ENABLE; 

    while((pDMA->DMA_INT_CPU_SR & DMA_INT_M0) == 0x0);

    pDMA->DMA_INT_CPU_SR |= DMA_INT_M0; //Clean interrupt status
#endif

    return MMP_ERR_NONE;
}
//------------------------------------------------------------------------------
//  Function    : MMPF_DMA_MoveData1
//  Description :
//  Note        : 1. The function doesn't use in ISR, because it called MMPF_OS_AcquireSem.
//                2. The execute time of DMARetFun must transient, because MMPF_DMA_ISR used the
//                   Callback function.
//------------------------------------------------------------------------------
MMP_ERR MMPF_DMA_MoveData1(MMP_ULONG ulSrcaddr, MMP_ULONG ulDstaddr,
								  MMP_ULONG ulCount, DmaCallBackFunc *CallBackFunc)
{
    return MMPF_DMA_MoveData0(ulSrcaddr, ulDstaddr, ulCount, NULL, CallBackFunc);
}

//------------------------------------------------------------------------------
//  Function    : MMPF_DMA_RotateData0
//  Description :
//  Note        : 1. The function doesn't use in ISR, because it called MMPF_OS_AcquireSem.
//                2. The execute time of DMARetFun must transient, because MMPF_DMA_ISR used the
//                   Callback function.
//------------------------------------------------------------------------------
MMP_ERR MMPF_DMA_RotateData0(MMP_ULONG ulSrcaddr, MMP_ULONG ulDstaddr,
						     MMP_ULONG ulSrcOffset, MMP_ULONG ulDstOffset, MMP_ULONG ulWidth, MMP_ULONG ulHeight, 
							 MMP_ULONG ctl_type, MMP_ULONG mirror_type, DmaCallBackFunc *CallBackFunc)
{
	AITPS_DMA pDMA = AITC_BASE_DMA;
	#if OS_CRITICAL_METHOD == 3
    OS_CPU_SR   cpu_sr = 0;
	#endif

    if (gbDmaFreeR0 == MMP_FALSE) {
        pDMA->DMA_INT_CPU_SR = DMA_INT_R0;
        RTNA_DBG_Str(0, "DMA_R busy\r\n");
        return 1;
    }

    if ((ulWidth > 0x2000) || (ulHeight > 0x2000)) {
        RTNA_DBG_Short(0, ulWidth);
        RTNA_DBG_Short(0, ulHeight);
        RTNA_DBG_Str(0, "DMA_R wrong width/height\r\n");
    }

    gbDmaEnCount++;
    gbDmaFreeR0 = MMP_FALSE;
    CallBackFuncR0 = CallBackFunc;

    pDMA->DMA_R[MMPF_DMA_R_0].DMA_R_SRC_ADDR = ulSrcaddr;
    pDMA->DMA_R[MMPF_DMA_R_0].DMA_R_DST_ADDR = ulDstaddr;
    pDMA->DMA_R[MMPF_DMA_R_0].DMA_R_SRC_OFST = ulSrcOffset;
	pDMA->DMA_R[MMPF_DMA_R_0].DMA_R_DST_OFST = ulDstOffset;
	pDMA->DMA_R[MMPF_DMA_R_0].DMA_R_PIX_W = ulWidth - 1;
	pDMA->DMA_R[MMPF_DMA_R_0].DMA_R_PIX_H = ulHeight - 1;
	pDMA->DMA_R[MMPF_DMA_R_0].DMA_R_CTL = ctl_type;
	pDMA->DMA_R[MMPF_DMA_R_0].DMA_R_MIRROR_EN = mirror_type;

    pDMA->DMA_INT_CPU_SR = DMA_INT_R0;
    OS_ENTER_CRITICAL();
    pDMA->DMA_INT_CPU_EN |= DMA_INT_R0; //TBD, check if enabled at dma init
    OS_EXIT_CRITICAL();

    pDMA->DMA_EN = DMA_R_ENABLE; 

	return MMP_ERR_NONE;
}
//------------------------------------------------------------------------------
//  Function    : MMPF_DMA_MoveRotate1
//  Description :
//  Note        : 1. The function doesn't use in ISR, because it called MMPF_OS_AcquireSem.
//                2. The execute time of DMARetFun must transient, because MMPF_DMA_ISR used the
//                   Callback function.
//------------------------------------------------------------------------------
MMP_ERR MMPF_DMA_RotateData1(MMP_ULONG ulSrcaddr, MMP_ULONG ulDstaddr,
								  MMP_ULONG ulOffset, MMP_ULONG ulWidth, MMP_ULONG ulHeight,
								  MMP_ULONG ctl_type, MMP_ULONG mirror_type, DmaCallBackFunc *CallBackFunc)
{
#if 0//(CHIP == P_V2)
	AITPS_DMA pDMA = AITC_BASE_DMA;

    gbDmaEnCount++;
	gbDmaFreeR1 = MMP_FALSE;
    CallBackFuncR1 = CallBackFunc;

	pDMA->DMA_R[MMPF_DMA_R_1].DMA_R_SRC_ADDR = ulSrcaddr;
	pDMA->DMA_R[MMPF_DMA_R_1].DMA_R_DST_ADDR = ulDstaddr;
    pDMA->DMA_R[MMPF_DMA_R_1].DMA_R_SRC_OFST = ulOffset;
    pDMA->DMA_R[MMPF_DMA_R_1].DMA_R_DST_OFST = ulOffset;
	pDMA->DMA_R[MMPF_DMA_R_1].DMA_R_PIX_W = (ulWidth & 0x1FFF)-1;
	pDMA->DMA_R[MMPF_DMA_R_1].DMA_R_PIX_H = (ulHeight & 0x1FFF)-1;
	pDMA->DMA_R[MMPF_DMA_R_1].DMA_R_CTL = ctl_type;
	pDMA->DMA_R[MMPF_DMA_R_1].DMA_R_MIRROR_EN = mirror_type;

    pDMA->DMA_INT_CPU_EN |= DMA_INT_R1;

	pDMA->DMA_R1_EN = DMA_ENABLE;
#endif
    return MMP_ERR_NONE;
}
#else
void MMPF_DMA_ISR(void)
{
}
#endif
